﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Xml.Linq;
using Medianamik.Core.Cache;
using Medianamik.Core.Interfaces;

namespace Medianamik.Core.Lock
{
    public static class LockManager
    {
        /// Libere le verrou sur un object
        /// </summary>
        /// <param name="pObjectId"></param>
        public static void UnlockObject(Guid pObjectId)
        {
            DALProviderManager.DALProvider.ConfigDALProvider.DestroyLockByObjectId(pObjectId);
            var locks = LockCacheManager.Instance.Where(l => l.LockObject == pObjectId).ToList();
            locks.ForEach(l => LockCacheManager.Instance.Remove(l));
        }

        public static void DeleteLock(Guid pLockId)
        {
            DALProviderManager.DALProvider.ConfigDALProvider.DestroyLockByLockId(pLockId);
            var locks = LockCacheManager.Instance.Where(l => l.LockId == pLockId).ToList();
            locks.ForEach(l => LockCacheManager.Instance.Remove(l));
        }

        /// <summary>
        /// Retourne la liste Lock pour un objet
        /// Il peut y avoir plusieurs Locks pour un object (Inactifs ou Expires)
        /// </summary>
        /// <param name="pObjectId"></param>
        /// <returns></returns>
        public static Collection<ILock> GetLocksByObjectId(Guid pObjectId)
        {
            return new Collection<ILock>(LockCacheManager.Instance.Where(l => l.LockObject  == pObjectId).ToList());
            
        }

        /// <summary>
        /// Retourne les info de Lock pour l'objet demandé
        /// Si aucun Lock "Alive", n'est trouvé, on retourne le Singleton LockInfo.Empty
        /// </summary>
        /// <param name="pObjectId"></param>
        /// <returns></returns>
        public static LockInfo GetInfo(Guid pObjectId)
        {
            var lk = LockCacheManager.Instance.Where(l => l.LockObject == pObjectId)
                .FirstOrDefault();
            //.FirstOrDefault(l => l.IsAlive());  -> on veut afficher message même si n'est plus Alive...

            return GetInfo(lk);

        }

        private static LockInfo GetInfo(ILock pLock)
        {
            if (pLock == null)
                return null;

            var activationDate = pLock.ActivationDate ?? DateTime.MinValue;
            return new LockInfo(pLock.UserInfo, activationDate, TimeSpan.FromSeconds(pLock.Ultimatum), pLock.LockObject);
            
        }

        /// <summary>
        /// Vérifie si un Object est vérouillé
        /// Cette méthode utilise une liste en Cache pour plus d'éfficacité
        /// </summary>
        /// <param name="pObjectId"></param>
        /// <returns></returns>
        public static bool IsLocked(Guid pObjectId)
        {

            return LockCacheManager.Instance.Where(l => l.LockObject == pObjectId)
                .Any(l => l.IsAlive());
        }

        /// <summary>
        /// Vérouille un objet
        /// </summary>
        /// <param name="pTransacId">Id de Transaction, issu du Cookie de transaction</param>
        /// <param name="pObjectId">Id de l'objet a verouiller</param>
        /// <param name="pUltimatum">Durée du vérouillage</param>
        /// <param name="pUserName">Nom de l'utilisateur</param>
        /// <returns></returns>
        public static ILock CreateLock(Guid pTransacId, Guid pObjectId, TimeSpan pUltimatum, string pUserName)
        {
            var lk =  DALProviderManager.DALProvider.ConfigDALProvider.CreateLock(pTransacId, pObjectId, pUltimatum, pUserName);
            LockCacheManager.Instance.Add(lk);
            return lk;
            
        }

        /// <summary>
        /// Met à jour un verrou
        /// Si le verrou nést pas actif, il est activé 
        /// </summary>
        /// <param name="currentLock"></param>
        public static void UpdateLock(ILock pLock)
        {
            if (!pLock.ActivationDate.HasValue)
            {
                pLock.ActivationDate = DateTime.Now;
            }
            pLock.LastCall = DateTime.Now;
            DALProviderManager.DALProvider.ConfigDALProvider.UpdateLock(pLock.LockId, pLock.ActivationDate.Value , pLock.LastCall.Value );
            LockCacheManager.Instance.Update(pLock);
            
        }

        public static ILock[] GetLocks(int pPageIndex, int pPageSize)
        {
            return LockCacheManager.Instance.Skip(pPageIndex * pPageSize).Take(pPageSize).ToArray();
        }

        public static void CleanUpLocks()
        {
            var allLocks = DALProviderManager.DALProvider.ConfigDALProvider.GetLocks(1, int.MaxValue);
            var expiredLocks = allLocks.Where(l => !l.IsAlive());
            foreach (var lk in expiredLocks)
            {
                DeleteLock(lk.LockId);
                LockCacheManager.Instance.Remove(lk);
            }
        }
    }
}